
package ija.model.figures;

import ija.model.basis.Figure;
import ija.model.basis.Position;
import ija.model.types.FigureColor;
import ija.model.types.FigureDirection;
import ija.model.types.FigureRoute;
import ija.model.types.Tree;
import ija.xls.notation.DeskCoordinate;


/**
 * Třída reprezentuje běžný kámen ve hře dáma
 * 
 * @author Radek Necas, xnecas18
 */
public class Piece extends CheckersFigure {

    /** Směr pohybu pěšce */
	FigureDirection direction;
    
    /**
     * 
     * @param p pozice, kam bude kámen umístěn.
     * @param c barva kamene.
     * @param d směr hry kamene (dopředu znamená pohyb z nižšího řádku na vyšší).
     */
    public Piece(Position p, FigureColor c, FigureDirection d) {
        super(p, c);
        direction = d;
    }
    
    /**
     * Konstruktor figurky pomoci figurky z jine sachovnice
     * @param p pozice figurky na aktualni sachovnici
     * @param copyPiece figurka, ze ktere se budou kopirovat udaje
     */
    public Piece(Position p, Piece copyPiece) {
        super(p, copyPiece);
        direction = copyPiece.getDirection();
    }
    
    /**
     * Metoda pro ziskani vsech beznych pohybu (nezahrnuje skoky)
     * @return seznam všech možných běžných pohybů. Pokud není žádný pohyb nalezen je seznam prázdný
     */
    @Override
    public boolean getMoves(Tree.Node<FigureRoute> root) {
        int dR = (direction == FigureDirection.FORWARD ? 1 : -1);
        boolean find = false;
        
        // Zkouska pohybu vlevo
        Position p = this.position.nextPosition(-1,dR);
        if(p != null && this.canMove(p)) {
            root.addChild(new FigureRoute(new DeskCoordinate(p), root.getData().getText() + "-" + p.toString()));
            find = true;
        }
        
        // Zkouska pohybu vpravo
        p = this.position.nextPosition(1, dR);
        if(this.canMove(p)) {
            root.addChild(new FigureRoute(new DeskCoordinate(p), root.getData().getText() + "-" + p.toString()));
            find = true;
        }
        
        return find;
    }
    
    /**
     * Metoda přidá pozici pro skok.
     * Pokud skok není možný nepřidá se.
     * 
     * @param gm list do něhož bude skok přidán.
     * @param  dC rozdíl sloupce (při skoku vlevo -2 při skoku vpravo 2).
     * @return figurku jenž by byla při skoku vyhozena. Pokud skok není možné provést tak null.
     */
    public Figure addJump(Tree.Node<FigureRoute> parrent, int dC) {
        int dR = (direction == FigureDirection.FORWARD ? 2 : -2);
        
        Position p = this.position.nextPosition(dC,dR);
        if(p == null) 
            return null;
        
        if(p == null)
            return null;
        
        Position jumpedPos = this.canJump(p);
        if(jumpedPos == null)
            return null;
        
        Figure jumpedFigure = jumpedPos.getFigure();
        if(jumpedFigure != null) {
            parrent.addChild(new FigureRoute(new DeskCoordinate(p), parrent.getData().getText() + "x" + p.toString()));
            return jumpedFigure;
        }
        
        return null;
    }
    
    /**
     * Metoda pro naplnění pozic všech možných skoků.
     * Umožňuje víceskoky. Rekurzivně volá sebe sama.
     * @param gm
     * @return 
     */
    @Override
    public boolean getJumps(Tree.Node<FigureRoute> parrent) {        
        Position jumpedPos;
        Position oldPos = position;
        Position newPos;
        
        
        // Skoceni doleva
        Figure fLeft = addJump(parrent, -2);
        if(fLeft != null) {
            // Ulozeni stavu
            if(direction == FigureDirection.FORWARD)
                newPos = this.position.nextPosition(-2, 2);
            else
                newPos = this.position.nextPosition(-2, -2);
            
            jumpedPos = fLeft.getPosition();
            // Provedeni skoku
            //jump(newPos);
            this.uncheckedMove(newPos);
            jumpedPos.removeFigure();
            getJumps(parrent.getChild(new FigureRoute(new DeskCoordinate(newPos), null)));
            // Vraceni stavu
            this.uncheckedMove(oldPos);
            jumpedPos.putFigure(fLeft);
        }
        
        // Skoceni doprava
        Figure fRight = addJump(parrent, 2);
        if(fRight != null) {
            // Ulozeni stavu
            if(direction == FigureDirection.FORWARD)
                newPos = this.position.nextPosition(2, 2);
            else
                newPos = this.position.nextPosition(2, -2);
            jumpedPos = fRight.getPosition();
            // Provedeni skoku
            jump(newPos);
            getJumps(parrent.getChild(new FigureRoute(new DeskCoordinate(newPos), null)));
            // Vraceni stavu
            this.uncheckedMove(oldPos);         
            jumpedPos.putFigure(fRight);
        }
        else {
            if(fLeft == null) {         // Nenasel se skok ani vlevo ani vpravo
                return false;
            }
        }

        return true;
    }
    
    /**
     * Nastavení směru kamene
     * @param d směr pohybu na který se má kámen nastavit.
     */
    public void setDirection(FigureDirection d) {
        direction = d;
    }
    
    /**
     * Metoda pro získání směru kamene
     * @return směr jakým se kamen pohybuje
     */
    public FigureDirection getDirection() {
        return direction;
    }

    @Override
    public Position canJump(Position endPosition) {
        if(!position.sameDiagonal(endPosition) || endPosition.getFigure() != null)
            return null;
        
        int dR = endPosition.getRowNumber() - position.getRowNumber();
        int dC = endPosition.getColumnChar() - position.getColumnChar();
        int expectedDR = (direction == FigureDirection.FORWARD ? 2 : -2);
        Position p;
        if(dR == expectedDR && (dC == 2 || dC == -2)) {
            p = position.nextPosition(dC/2, dR/2);     
            if(p == null || p.getFigure() == null)
                return null;
            
            if(p.getFigure().getColor() != color)
                return(p);
        }
        
        return null;
    }
    
    @Override
    public boolean inDirection(Position p){
        if(position.sameDiagonal(p)) {
            int dp = (direction == FigureDirection.FORWARD ? 1 : -1);
                     
            if((p.getRowNumber() - position.getRowNumber()) == dp) {         // Bezny posun o jednu pozici
                return true;
            }
        }    
        return false;	
    }
    
    @Override
    public boolean canMove(Position p) {
        if(p == null)
            return false;
        
        if(p.getFigure() != null)
            return false;
        if (!(p.getDesk().isInside(p)))
        	return false;
        
        return inDirection(p);
    }
}
